/*
 * DefaultRemoteTableModelListener.java
 * 
 * Written by Joseph Bowbeer and released to the public domain,
 * as explained at http://creativecommons.org/licenses/publicdomain
 */

package jozart.remotetable;

import java.awt.EventQueue;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import javax.swing.table.DefaultTableModel;

/**
 * Receives callbacks from a remote table model and transfers the changes to
 * a local model (on the event-dispatch thread).
 * <p>
 * The local model is required to be a DefaultTableModel in order to leverage
 * its support for insertion and deletion of rows. Changes to the column
 * structure are not supported.
 * 
 * @author Joseph Bowbeer
 * @version 1.0
 */
public class DefaultRemoteTableModelListener extends UnicastRemoteObject
    implements RemoteTableModelListener {

    /** Local model. */
    private final DefaultTableModel model;

    /**
     * Constructs a remote listener to update a local model.
     * 
     * @param model local model to update
     */
    public DefaultRemoteTableModelListener(DefaultTableModel model)
        throws RemoteException {
        this.model = model;
    }

    /**
     * Updates the local model on the event-dispatch thread.
     *
     * @param event {@inheritDoc}
     * @throws IllegalStateException if column structure changed
     */
    public void remoteTableChanged(final RemoteTableModelEvent event) {
        Runnable doUpdate = new Runnable() {
            public void run() {
                int type = event.getType();
                int firstRow = event.getFirstRow();
                int lastRow = event.getLastRow();

                if (firstRow == RemoteTableModelEvent.HEADER_ROW) {
                    new IllegalStateException("header change");
                }

                switch (type) {
                    case RemoteTableModelEvent.UPDATE:
                        if (lastRow != Integer.MAX_VALUE) {
                            /* Partial update. */
                            event.setValues(model);
                            break;
                        }

                        /*
                         * Full update - remove old rows and
                         * fall through to insert new rows.
                         */
                        model.setNumRows(0);

                    case RemoteTableModelEvent.INSERT:
                        Object[] data = (Object[]) event.getData();
                        if (firstRow == lastRow) {
                            model.insertRow(firstRow, data);
                        } else {
                            for (int i = 0; i < data.length; i++) {
                                model.insertRow(firstRow+i, (Object[]) data[i]);
                            }
                        }
                        break;

                    case RemoteTableModelEvent.DELETE:
                        for (int row = lastRow; row >= firstRow; --row) {
                            model.removeRow(row);
                        }
                        break;
                }
            }
        };
        EventQueue.invokeLater(doUpdate);
    }
}
